<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="coinfaces">

        <title>strptime的误解</title>

    <link rel="stylesheet" href="../../theme/css/style.css">
    <link rel="stylesheet" href="../../theme/css/pygments.css">



</head>

<body>
    <div class="content">
<h1>strptime的误解</h1>    <p>
        under
            <a href="../../tags/python/">python</a>
    </p>
    <p>
        in <a href="../../categories/tech/">tech</a>
    </p>
    <p>Published: 2016-10-13</p>


    <p><tt class="docutils literal">strptime</tt>在解析%Y%m%d%H%M%S这样的格式时，有时位数不足14位仍能正确解析，以前以为不足的部分（时、分、秒）用0补充，但试验后发现不是。</p>
<pre class="literal-block">
&gt;&gt;&gt; from datetime import datetime
&gt;&gt;&gt; datetime.strptime('20151111000000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
&gt;&gt;&gt; datetime.strptime('2015111100000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
&gt;&gt;&gt; datetime.strptime('201511110000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
&gt;&gt;&gt; datetime.strptime('20151111000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
&gt;&gt;&gt; datetime.strptime('2015111100', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 1, 1, 0)
&gt;&gt;&gt; datetime.strptime('201511110', '%Y%m%d%H%M%S')
datetime.datetime(2015, 1, 1, 1, 1)
&gt;&gt;&gt; datetime.strptime('20151111', '%Y%m%d%H%M%S')
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;/usr/lib/python2.7/_strptime.py&quot;, line 325, in _strptime
    (data_string, format))
ValueError: time data '20151111' does not match format '%Y%m%d%H%M%S'
</pre>
<p>除了年必须是4位的，从月到秒都可以只有1位，看过源码后发现确实如此，_strptime使用正则表达式实现的，所涉及的各部分正则表达式定义如下：</p>
<div class="highlight"><pre><span></span><span class="s1">&#39;Y&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;Y&gt;\d\d\d\d)&quot;</span><span class="p">,</span>
<span class="s1">&#39;m&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;m&gt;1[0-2]|0[1-9]|[1-9])&quot;</span><span class="p">,</span>
<span class="s1">&#39;d&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;d&gt;3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])&quot;</span><span class="p">,</span>
<span class="s1">&#39;H&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;H&gt;2[0-3]|[0-1]\d|\d)&quot;</span><span class="p">,</span>
<span class="s1">&#39;M&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;M&gt;[0-5]\d|\d)&quot;</span><span class="p">,</span>
<span class="s1">&#39;S&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s2">&quot;(?P&lt;S&gt;6[0-1]|[0-5]\d|\d)&quot;</span><span class="p">,</span>
</pre></div>
<p>唯一的要求是字符串和格式能完全匹配，即使有歧义也没关系，不能完全匹配则会抛出<tt class="docutils literal">ValueError</tt>异常。</p>
<div class="highlight"><pre><span></span><span class="n">found</span> <span class="o">=</span> <span class="n">format_regex</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">data_string</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">found</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;time data </span><span class="si">%r</span><span class="s2"> does not match format </span><span class="si">%r</span><span class="s2">&quot;</span> <span class="o">%</span>
                     <span class="p">(</span><span class="n">data_string</span><span class="p">,</span> <span class="nb">format</span><span class="p">))</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data_string</span><span class="p">)</span> <span class="o">!=</span> <span class="n">found</span><span class="o">.</span><span class="n">end</span><span class="p">():</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;unconverted data remains: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span>
                      <span class="n">data_string</span><span class="p">[</span><span class="n">found</span><span class="o">.</span><span class="n">end</span><span class="p">():])</span>
</pre></div>
<p>这样处理是合适的，如何使用不产生歧义是用户的责任，不应该让<tt class="docutils literal">datetime</tt>库来背。如果不想产生歧义，有两种解决方式：</p>
<ul class="simple">
<li>在时间的不同部分间插入分隔符，不要使用类似<tt class="docutils literal">%Y%m%d%H%M%S</tt>的格式。</li>
<li>使用<tt class="docutils literal">%Y%m%d%H%M%S</tt>时检查给的字符串是否是14位，不足14位时都有可能产生歧义。</li>
</ul>
<p>（完）</p>

    </div>
<nav class="nav sidebar">
    <div class="siteinfo">
        <div class="sitename"><a href="../..">coinfaces</a></div>
        <div class="tagline">Another Side of Life</div>
    </div>

        <a href="../../categories/">categories</a>
        <a href="../..">&larr; Home</a>
</nav><footer class="footer">
    <span>
        &copy; jpli &middot;
        under <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">CC-BY-SA 4.0</a>
    </span>
    |
    <span>
        Powered by:
        <a href="http://blog.getpelican.com/">Pelican</a>
    </span>
</footer></body>
</html>